<?php

	/* dependence */
	CoreProject::Using('core.socket');
	
	/**
	 * @package		CoreProject
	 * @subpackage	Libs
	 *
	 * cpr_Libs_SmtpMessage
	 * cpr_Libs_SmtpConfig
	 * cpr_Libs_Smtp
	 *
	 */

	class cpr_Libs_SmtpMessage
	{
		/**
		 * @var	string
		 */
		private $_from;
		
		/**
		 * @var	array
		 */
		private $_to = array();
		
		/**
		 * @var	string
		 */
		private $_message;
		
		/**
		 * @param	string	$_from
		 */
		public function SetFrom($_from)
		{
			 $this->_from = trim($_from);
		}
		
		/**
		 * @param	string	$_to
		 */
		public function AddTo($_to)
		{
			 $this->_to[] = trim($_to);
		}
		
		/**
		 * @param	string	$_rawbody
		 */
		function SetMessageRawBody($_rawbody)
		{
			$this->_message = $_rawbody;
		}
		
		/**
		 * @return	string
		 */
		function ToAsArray()
		{
			return $this->_to;
		}
		
		/**
		 * @return	string
		 */
		function FromAsString()
		{
			return $this->_from;
		}

		/**
		 * @return	string
		 */
		function RawBodyAsString()
		{
			return $this->_message;
		}
	}

	class cpr_Libs_SmtpConfig
	{
		/**
		 * @var	string
		 */
		private $_smtpLogin;
		
		/**
		 * @var	string
		 */
		private $_smtpPassword;
		
		/**
		 * @var	bool
		 */
		private $_smtpAuth;

		/**
		 * @param	string	$_login
		 * @param	string	$_password
		 * @param	bool	$_auth = true
		 * @return	cpr_Libs_SmtpConfig
		 */
		public function __construct($_login, $_password, $_auth = true)
		{
			$this->_smtpLogin = $_login;
			$this->_smtpPassword = $_password;
			$this->_smtpAuth = $_auth;
		}

		/**
		 * @return	string
		 */
		public function Login()
		{
			return $this->_smtpLogin;
		}
		
		/**
		 * @return	string
		 */
		public function Password()
		{
			return $this->_smtpPassword;
		}

		/**
		 * @return	bool
		 */
		public function IsAuth()
		{
			return $this->_smtpAuth;
		}
	}
	
	class cpr_Libs_Smtp extends cpr_Core_Socket
	{
		const LOG_CLASSNAME = 'smtp';
		
		/**
		 * @var	cpr_Libs_SmtpConfig
		 */
		private $_smtpConfig;
		
		/**
		 * @param	cpr_Core_SocketConfig	$_config
		 * @param	cpr_Libs_SmtpConfig	$_smtpConfig = null
		 */
		public function __construct($_socketConfig, $_smtpConfig = null)
		{
			parent::__construct($_socketConfig);
			$this->_smtpConfig = $_smtpConfig;
		}
		
		/**
		 * @return	bool
		 */
		public function Connect()
		{
			return parent::Connect(self::LOG_CLASSNAME) && $this->_isSuccess();
		}
		
		/**
		 * @return	bool
		 */
		public function Disconnect()
		{
			return $this->_executeCommand('QUIT') && parent::Disconnect();
		}

		function  __destruct()
		{
			$this->Disconnect();
		}

		/**
		 * @param	cpr_Libs_SmtpMessage	$_smtpMessage
		 * @return	bool
		 */
		public function Send($_smtpMessage)
		{
			if (null === $this->_smtpConfig || null === $_smtpMessage)
			{
				return false;
			}
			
			$_helloMessage = $this->_getDomainFromEmail($_smtpMessage->FromAsString());
			if (!$this->_executeCommand('EHLO '.$_helloMessage))
			{
				if (!$this->_executeCommand('HELO '.$_helloMessage))
				{
					return false;
				}
			}

			if ($this->_smtpConfig->IsAuth())
			{
				if (!$this->_executeCommand('AUTH LOGIN') ||
					!$this->_executeCommand(base64_encode($this->_smtpConfig->Login())) ||
					!$this->_executeCommand(base64_encode($this->_smtpConfig->Password())))
				{
					return false;
				}
			}

			$_to = $_smtpMessage->ToAsArray();
			$_to = array_unique($_to);

			if (count($_to) == 0)
			{
				if (!$this->_executeCommand('MAIL FROM:<'.$_smtpMessage->FromToString().'>'))
				{
					return false;
				}
			}
			else
			{
				$this->setError(self::LOG_CLASSNAME.': recipients not founds.');
				return false;
			}
			
			foreach ($_to as $_recipient)
			{
				if (!$this->_executeCommand('RCPT TO:<'.$_recipient.'>'))
				{
					return false;
				}
			}

			if ($this->_executeCommand('DATA') &&
				$this->_executeCommand($this->_prepareDataForSend($_smtpMessage->RawBodyAsString())))
			{
				return true;
			}
			
			return false;
		}

		/**
		 * @param	string	$_rawBody
		 * @return	string
		 */
		private function _prepareDataForSend($_rawBody)
		{
			return str_replace(CPR_CRLF.'.', CPR_CRLF.'..', $_rawBody).CPR_CRLF.'.';
		}
		
		/**
		 * @param	string	$_command
		 * @return	bool
		 */
		private function _executeCommand($_command)
		{
			return $this->putLine($_command, self::LOG_CLASSNAME) && $this->_isSuccess();
		}
		
		/**
		 * @return	bool
		 */
		private function _isSuccess()
		{
			$_result = true;
			do
			{
				$_line = $this->getLine(self::LOG_CLASSNAME);
				if (false === $_line)
				{
					$_result = false;
					break;
				}
				else
				{
					$_line = str_replace(array("\r", "\n"), '', $_line);
					if (substr($_line, 0, 1) != '2' && substr($_line, 0, 1) != '3')
					{
						$_result = false;
						$this->setError(self::LOG_CLASSNAME.': response not success ('.$_line.').');
						break;
					}
				}
			  
			} while (substr($_line, 3, 1) === '-');
			
			return $_result;
		}
		
		/**
		 * @param	string	$email
		 * @return	string
		 */
		private function _getDomainFromEmail($_email)
		{
			if ($_email)
			{
				$_dPos = strpos($_email, '@');
				if (false !== $_dPos)
				{
					return substr($_email, $_dPos + 1);
				}
			}
			
			return $_email;
		}
	}
